package com.sinosoft.lk.core.client;

import com.sinosoft.lk.core.client.impl.SsoDefaultLoginSuccessCallBackImpl;
import com.sinosoft.lk.core.config.SsoClientFilterConfig;
import com.sinosoft.lk.core.constants.SsoConstants;
import com.sinosoft.lk.core.constants.SsoHttpHeader;
import com.sinosoft.lk.core.controller.client.AuthenticationController;
import com.sinosoft.lk.core.helper.JedisHelper;
import com.sinosoft.lk.core.utils.AntPathMatcher;
import com.sinosoft.lk.core.utils.CookieUtils;
import com.sinosoft.lk.core.utils.StringUtils;
import java.io.IOException;
import java.util.Set;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @Author 绫小路
 * @Date 2021/3/4
 */
public class SsoClientFilter implements Filter {

  private static Logger logger = LoggerFactory.getLogger(SsoClientFilter.class);
  private AntPathMatcher matcher = new AntPathMatcher();
  private SsoClientFilterConfig ssoClientFilterConfig;
  private Set<String> excludedPaths;
  private boolean responseIsJson;
  private String loginPath;
  private SsoLoginSuccessCallBack ssoLoginSuccessCallBack;
  private String clientName;
  private String ssoSessionIdName;

  public SsoClientFilterConfig getSsoClientFilterConfig() {
    return ssoClientFilterConfig;
  }

  public void setSsoClientFilterConfig(SsoClientFilterConfig ssoClientFilterConfig) {
    //1、set Argument
    this.ssoClientFilterConfig = ssoClientFilterConfig;
    excludedPaths = ssoClientFilterConfig.getExcludedPaths();
    responseIsJson = ssoClientFilterConfig.isJson();
    loginPath = ssoClientFilterConfig.getLoginPath();
    ssoLoginSuccessCallBack = ssoClientFilterConfig.getSsoLoginSuccessCallBack();
    clientName = ssoClientFilterConfig.getClientName();
    ssoSessionIdName = ssoClientFilterConfig.getSsoSessionIdName();

    //2、valid
    if (StringUtils.isEmpty(loginPath)) {
      throw new IllegalArgumentException("loginPath not empty!");
    }
    if (StringUtils.isEmpty(ssoSessionIdName)) {
      ssoSessionIdName = SsoConstants.SESSION_ID;
    }
    if (ssoLoginSuccessCallBack == null) {
      ssoLoginSuccessCallBack = new SsoDefaultLoginSuccessCallBackImpl();
    }

    //3、init redis
    JedisHelper.setConfig(
        ssoClientFilterConfig.getJedisAddress(),
        ssoClientFilterConfig.getJedisPoolConfig(),
        ssoClientFilterConfig.getJedisConnectionTimeout()
    );
    JedisHelper instance = JedisHelper.getInstance();
    if (instance.ping()) {
      logger.info("--------------init jedisUtils instance finish !------------------");
      //logger.error("connect redis fail! please check config!");
      //throw new Exception("connect redis fail! please check config!");
    }
  }

  @Override
  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
      throws IOException, ServletException {
    HttpServletRequest request = (HttpServletRequest) servletRequest;

    String uri = request.getRequestURI();

    // 1、excluded paths
    for (String path : excludedPaths) {
      if (matcher.match(uri, path)) {
        // allow
        filterChain.doFilter(servletRequest, servletResponse);
        return;
      }
    }

    //2、check sessionId
    boolean check = AuthenticationController.check(request, ssoSessionIdName);
    if (!check) {
      HttpServletResponse response = (HttpServletResponse) servletResponse;
      // one、check is login success？
      String token = request.getParameter(SsoConstants.SSO_TOKEN);
      if (!StringUtils.isEmpty(token)) {
        boolean hasToken = JedisHelper.exists(token);
        if (hasToken) {
          //set cookie
          CookieUtils.setCookie(SsoConstants.SESSION_ID, token, response);

          //login success callback
          ssoLoginSuccessCallBack.success(request, response, JedisHelper.getStrHash(token));

          // allow
          filterChain.doFilter(servletRequest, servletResponse);
          return;
        }
      }

      // two、jump sso login
      StringBuffer url = request.getRequestURL();
      if (responseIsJson) {
        // json message
        response.setContentType(SsoHttpHeader.ContentType_JSON);
        response.getWriter().println(SsoConstants.JSON_403_MSG);
      } else {
        // redirect login
        response.sendRedirect(loginPath + "?" + SsoConstants.SERVICE + "=" + url);
      }
      logger.warn("check fail, http code:403, request url={}", url);

      // clear cookies

      // end
      return;
    }

    // 3、auth ok!
    filterChain.doFilter(servletRequest, servletResponse);
  }

}
